//SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package board_dao

import (
	"context"
	"fmt"

	"gitcode.com/eteam/api-server/dao/common"
	"gitcode.com/eteam/proto-gen-go.git/board_member_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type MemberInfoDbItem struct {
	InfoId       string `bson:"_id"` //自动生成
	MemberUserId string `bson:"memberUserId"`
	BoardId      string `bson:"boardId"`
	LastViewTime int64  `bson:"lastViewTime"`
	CreateTime   int64  `bson:"createTime"`
	Admin        bool   `bson:"admin"`
}

func (item *MemberInfoDbItem) ToMemberInfo() *board_member_api.MemberInfo {
	return &board_member_api.MemberInfo{
		MemberUserId: item.MemberUserId,
		BoardId:      item.BoardId,
		LastViewTime: item.LastViewTime,
		Admin:        item.Admin,
	}
}

type _MemberInfoDao struct {
	mc *mongo.Collection
}

func newMemberInfoDao(db *mongo.Database) (*_MemberInfoDao, error) {
	mc := db.Collection(common.DB_NS_BOARD + "member")
	_, err := mc.Indexes().CreateMany(context.Background(), []mongo.IndexModel{
		{
			Keys: bson.D{{"boardId", 1}},
		},
		{
			Keys: bson.D{{"memberUserId", 1}},
		},
	})
	if err != nil {
		return nil, err
	}
	return &_MemberInfoDao{mc: mc}, nil
}

func (db *_MemberInfoDao) Insert(ctx context.Context, dbItem *MemberInfoDbItem) error {
	dbItem.InfoId = db.genInfoId(dbItem.BoardId, dbItem.MemberUserId)
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_MemberInfoDao) genInfoId(boardId, memberUserId string) string {
	return fmt.Sprintf("%s:%s", boardId, memberUserId)
}

func (db *_MemberInfoDao) Exist(ctx context.Context, boardId, memberUserId string) (bool, error) {
	infoId := db.genInfoId(boardId, memberUserId)
	query := bson.M{"_id": infoId}
	count, err := db.mc.CountDocuments(ctx, query)
	return count > 0, err
}

func (db *_MemberInfoDao) Get(ctx context.Context, boardId, memberUserId string) (*MemberInfoDbItem, error) {
	retItem := &MemberInfoDbItem{}
	infoId := db.genInfoId(boardId, memberUserId)
	err := db.mc.FindOne(ctx, bson.M{"_id": infoId}).Decode(retItem)
	return retItem, err
}

func (db *_MemberInfoDao) Remove(ctx context.Context, boardId, memberUserId string) error {
	infoId := db.genInfoId(boardId, memberUserId)
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": infoId})
	return err
}

func (db *_MemberInfoDao) RemoveByBoard(ctx context.Context, boardId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"boardId": boardId})
	return err
}

func (db *_MemberInfoDao) CountByBoard(ctx context.Context, boardId string) (uint32, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"boardId": boardId})
	return uint32(count), err
}

func (db *_MemberInfoDao) CountByAdmin(ctx context.Context, boardId string, admin bool) (uint32, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"boardId": boardId, "admin": admin})
	return uint32(count), err
}

func (db *_MemberInfoDao) ListByBoard(ctx context.Context, boardId string) ([]*MemberInfoDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"boardId": boardId},
		options.Find().SetSort(bson.M{"createTime": 1}))
	if err != nil {
		return nil, err
	}
	retList := []*MemberInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_MemberInfoDao) ListByMember(ctx context.Context, memberUserId string, filterByBoard bool, boardIdList []string) ([]*MemberInfoDbItem, error) {
	query := bson.M{"memberUserId": memberUserId}
	if filterByBoard {
		if len(boardIdList) == 0 {
			return []*MemberInfoDbItem{}, nil
		}
		query["boardId"] = bson.M{"$in": boardIdList}
	}
	cursor, err := db.mc.Find(ctx, query)
	if err != nil {
		return nil, err
	}
	retList := []*MemberInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_MemberInfoDao) DistinctBoardId(ctx context.Context, memberUserId string) ([]string, error) {
	itemList, err := db.mc.Distinct(ctx, "boardId", bson.M{"memberUserId": memberUserId})
	if err != nil {
		return nil, err
	}
	retList := []string{}
	for _, item := range itemList {
		retList = append(retList, item.(string))
	}
	return retList, nil
}

func (db *_MemberInfoDao) DistinctMemberUserId(ctx context.Context, boardId string, filterByMemberUserId bool, memberUserIdList []string) ([]string, error) {
	query := bson.M{"boardId": boardId}
	if filterByMemberUserId {
		if len(memberUserIdList) == 0 {
			return []string{}, nil
		}
		query["memberUserId"] = bson.M{"$in": memberUserIdList}
	}
	itemList, err := db.mc.Distinct(ctx, "memberUserId", query)
	if err != nil {
		return nil, err
	}
	retList := []string{}
	for _, item := range itemList {
		retList = append(retList, item.(string))
	}
	return retList, nil
}

func (db *_MemberInfoDao) UpdateAdmin(ctx context.Context, boardId, memberUserId string, admin bool) error {
	infoId := db.genInfoId(boardId, memberUserId)
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": infoId}, bson.M{"$set": bson.M{
		"admin": admin,
	}})
	return err
}

func (db *_MemberInfoDao) UpdateLastViewTime(ctx context.Context, boardId, memberUserId string, lastViewTime int64) error {
	infoId := db.genInfoId(boardId, memberUserId)
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": infoId}, bson.M{"$set": bson.M{
		"lastViewTime": lastViewTime,
	}})
	return err
}
